use pest::Parser;
use pest_derive::Parser;

/// 由 pest_derive 根据 lexer.pest 生成解析器
#[derive(Parser)]
#[grammar = "src/lexer.pest"]
struct SysYLexer;

/// 记号种类（名称与题面/参考输出保持一致）
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// 关掉“类型名不符合驼峰命名”的警告（lint）。
#[allow(non_camel_case_types)]
pub enum TokenKind {
    // 关键字
    CONST, INT, VOID, IF, ELSE, WHILE, BREAK, CONTINUE, RETURN,
    // 终结符
    IDENT, INTEGER_CONST,
    // 运算符
    PLUS, MINUS, MUL, DIV, MOD, ASSIGN,
    EQ, NEQ, LT, GT, LE, GE, NOT, AND, OR,
    // 分隔符
    L_PAREN, R_PAREN, L_BRACE, R_BRACE, L_BRACKT, R_BRACKT, COMMA, SEMICOLON,
}

/// 单个词法单元：种类 + 文本 + 起始行号
/// 派生trait，Debug: 允许{?}, Clone: 可被克隆 Copy: 值在赋值时按位复制 PartialEq/Eq: 允许比较==
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LexToken {
    pub kind: TokenKind,
    pub text: String,   // 对 INTEGER_CONST，已转成十进制字符串；其余原样
    pub line: usize,    // 从 1 开始
}

impl TokenKind {
    /// 打印名：用于输出格式中的 [TOKEN_KIND]
    pub fn name(self) -> &'static str {
        use TokenKind::*;
        match self {
            CONST => "CONST", INT => "INT", VOID => "VOID",
            IF => "IF", ELSE => "ELSE", WHILE => "WHILE",
            BREAK => "BREAK", CONTINUE => "CONTINUE", RETURN => "RETURN",
            IDENT => "IDENT", INTEGER_CONST => "INTEGER_CONST",
            PLUS => "PLUS", MINUS => "MINUS", MUL => "MUL", DIV => "DIV", MOD => "MOD", ASSIGN => "ASSIGN",
            EQ => "EQ", NEQ => "NEQ", LT => "LT", GT => "GT", LE => "LE", GE => "GE", NOT => "NOT",
            AND => "AND", OR => "OR",
            L_PAREN => "L_PAREN", R_PAREN => "R_PAREN",
            L_BRACE => "L_BRACE", R_BRACE => "R_BRACE",
            L_BRACKT => "L_BRACKT", R_BRACKT => "R_BRACKT",
            COMMA => "COMMA", SEMICOLON => "SEMICOLON",
        }
    }
}

/// A 类词法错误：遇到“神秘字符”
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LexError {
    pub line: usize,
    pub ch: String, // 用 String 兼容可能的多字节字符
}

impl std::fmt::Display for LexError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Error type A at Line {}: Mysterious character \"{}\".",
            self.line, self.ch
        )
    }
}
impl std::error::Error for LexError {}

/// 词法分析：返回 (tokens, errors)
/// - 没有错误：tokens 用于打印
/// - 有错误：主程序打印所有错误（通常不再打印 token）
pub fn tokenize(input: &str) -> (Vec<LexToken>, Vec<LexError>) {
    use Rule::*;
    // 以顶层规则 `tokens` 解析整段输入
    let pairs = SysYLexer::parse(tokens, input).expect("pest driver failure");

    let mut out: Vec<LexToken> = Vec::new();
    let mut errors: Vec<LexError> = Vec::new();

    for p in pairs {
        for inner in p.into_inner() {
            match inner.as_rule() {
                // 正常 token：向下一层拿“叶子”规则（真正的终结符）
                Rule::token => {
                    let leaf = inner
                        .into_inner()
                        .next()
                        .expect("token should contain one leaf");

                    let raw = leaf.as_str();                      // 源文本切片
                    let (line, _col) = leaf.as_span().start_pos().line_col();

                    // 先确定种类
                    let kind = match leaf.as_rule() {
                        // 关键字
                        CONST => TokenKind::CONST,
                        INT => TokenKind::INT,
                        VOID => TokenKind::VOID,
                        IF => TokenKind::IF,
                        ELSE => TokenKind::ELSE,
                        WHILE => TokenKind::WHILE,
                        BREAK => TokenKind::BREAK,
                        CONTINUE => TokenKind::CONTINUE,
                        RETURN => TokenKind::RETURN,

                        // 终结符
                        IDENT => TokenKind::IDENT,
                        INTEGER_CONST => TokenKind::INTEGER_CONST,

                        // 运算符
                        EQ => TokenKind::EQ,
                        NEQ => TokenKind::NEQ,
                        LE => TokenKind::LE,
                        GE => TokenKind::GE,
                        AND => TokenKind::AND,
                        OR  => TokenKind::OR,
                        PLUS => TokenKind::PLUS,
                        MINUS => TokenKind::MINUS,
                        MUL => TokenKind::MUL,
                        DIV => TokenKind::DIV,
                        MOD => TokenKind::MOD,
                        ASSIGN => TokenKind::ASSIGN,
                        LT => TokenKind::LT,
                        GT => TokenKind::GT,
                        NOT => TokenKind::NOT,

                        // 分隔符
                        L_PAREN => TokenKind::L_PAREN,
                        R_PAREN => TokenKind::R_PAREN,
                        L_BRACE => TokenKind::L_BRACE,
                        R_BRACE => TokenKind::R_BRACE,
                        L_BRACKT => TokenKind::L_BRACKT,
                        R_BRACKT => TokenKind::R_BRACKT,
                        COMMA => TokenKind::COMMA,
                        SEMICOLON => TokenKind::SEMICOLON,

                        _ => unreachable!("unexpected leaf: {:?}", leaf.as_rule()),
                    };

                    // 再规范化文本：
                    // - INTEGER_CONST 统一转十进制字符串
                    // - 其余类型保持原文
                    let text = if matches!(kind, TokenKind::INTEGER_CONST) {
                        let val = if raw.starts_with("0x") || raw.starts_with("0X") {
                            i64::from_str_radix(&raw[2..], 16).unwrap()
                        } else if raw.len() > 1 && raw.starts_with('0') {
                            i64::from_str_radix(&raw[1..], 8).unwrap()
                        } else {
                            raw.parse::<i64>().unwrap()
                        };
                        val.to_string()
                    } else {
                        raw.to_string()
                    };

                    out.push(LexToken { kind, text, line });
                }

                // 错误字符：收集而不是立刻返回
                Rule::ERROR_CHAR => {
                    let span = inner.as_span();
                    let (line, _col) = span.start_pos().line_col();
                    errors.push(LexError {
                        line,
                        ch: inner.as_str().to_string(),
                    });
                }

                // 忽略：顶层容器与静默规则
                Rule::tokens | Rule::WS | Rule::LINE_COMMENT | Rule::MULTILINE_COMMENT => {}

                _ => unreachable!("unexpected rule: {:?}", inner.as_rule()),
            }
        }
    }

    (out, errors)
}
